#include "rgb.h"
#include "gpio.h"

#define delay300ns() \
	do               \
	{                \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
		__nop();     \
	} while (0) //实现300ns的时间  ，不同的Rgb灯所对应的参考手册不一样，本工程中使用到的Rgb灯点亮需要用到的300ns时间

	
	#define   RGBNUMBER   30             //宏定义每个RGB带，所对应的RGB灯颗数，本工程中用了两条rgb灯带，均包含30个灯；分别接在了PA10于PA7上，具体参考电路原理图

uint32_t ColorArr[RGBNUMBER] = {0};     //颜色设置数据，用于设置30颗灯的颜色，设置好颜色好，需要利用下面的RgbWrite函数与RgbUpData函数按照该数组设置好的颜色将RGB灯点亮

#define    ARR_SIZE(arr)   (sizeof(arr) / sizeof(arr[0]))    //获得数组的size（知识点，一定要记得，很好用）


uint32_t ColorChangeArr[] =                                       //颜色数组，用在RgbShow_FFT_Mode1()中进行颜色变换，该数组中的颜色可根据自己的需要，增、删、改
	{0xFFB6C100, 0xDC143C00, 0xC7158500, 0xFF00FF00, 0x9932CC00,
	 0x7B68EE00, 0x0000FF00, 0x1E90FF00, 0x20B2AA00, 0x2E8B5700,
	 0x00FF0000, 0xFFFF0000, 0xFFD70000, 0xFFA50000, 0xFF8C0000,
	 0xD2691E00, 0xFF450000, 0x00808000, 0x00008B00, 0x80008000};

	 
void Code0(uint8_t which_rgb)          //根据rgb灯带的参考手册，确认写入0的时序                            
{
	GPIOA->BSRR = (0x01 << which_rgb);   // PA端口指定的引脚（which_rgb），本工程中用到了PA10与PA7这两个引脚上接RGB灯带，因此本函数中传入10或7）
	delay300ns();
	GPIOA->BSRR = 0x01 << (which_rgb + 16);
	delay300ns();
	delay300ns();
	delay300ns();
}

void Code1(uint8_t which_rgb)         //根据rgb灯带的参考手册，确认写入1的时序
{
	GPIOA->BSRR = (0x01 << which_rgb);
	delay300ns();
	delay300ns();
	GPIOA->BSRR = 0x01 << (which_rgb + 16);
	delay300ns();
	delay300ns();
}

void RgbInit(void)            //Rgb初始化函数，目前本工程中就用到了PA10与PA7，因此配置此两个引脚即可，具体可参考电路图，增加Rgb灯带（本工程所使用的板子，最多可以接8根rgb灯带）
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	__HAL_RCC_GPIOA_CLK_ENABLE();

	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7 | GPIO_PIN_10, GPIO_PIN_RESET);

	GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void colorArrClear(void)                    // 将颜色全部清零。
{
	for (uint8_t i = 0; i < ARR_SIZE(ColorArr); i++)
	{
		ColorArr[i] = 0x00;
	}
}

void SetColorArr(uint32_t color, uint8_t pos) //设置ColorArr[pos],将color放入ColorArr数组的pos位，即将第pos个灯设置成color颜色
{
	ColorArr[pos] = color;
}

void SetColorArrs(uint32_t color, uint8_t StartPos, uint8_t len) //设置多个color至ColorArr数组中，起始位置为StartPos，长度为len
{
	colorArrClear();
	for (uint8_t i = StartPos; i < (StartPos + len); i++)
	{
		ColorArr[i % RGBNUMBER] = color;
	}
}

void RgbWrite(uint32_t *colorArr, uint8_t colorLen, uint8_t which_rgb) //将设置好的color[],写入到对应的rgb灯当中
{
	uint32_t color = 0x00;
	__disable_irq(); //暂停时钟中断，防止干扰

	for (uint8_t i = 0; i < colorLen; i++)
	{
		color = *(colorArr + i);
		
		/****** 以下4条语句，是为了将R（红色）位与G（绿色）位做交换，因为在调试过程中发现购买的Rgb灯带红色分量和绿色分量相反 ，如果其他灯带红绿色分量不相反则不需要以下4条语句*********/
		uint8_t r = (color >> 24);
		uint8_t g = (color >> 16);
		color = color & 0xffff;
		color = color | (g << 24) | (r << 16);
	
		
		for (uint8_t j = 0; j < 32; j++)         //对每颗灯所要写入的颜色的每一位（共计32位）进行判断，然后进行颜色的写入
		{
			if ((color & 0x80000000) == 0)
			{
				Code0(which_rgb);            
			}
			else
			{
				Code1(which_rgb);
			}
			color = color << 1;
		}
	}

	Code1(which_rgb);      //颜色写完后，空闲时，拉成高电平（参考Rgb灯带的参考手册）
	__enable_irq();       //打开时钟中断
}


void RgbUpData(uint8_t which_rgb)         //对Rgb灯带进行更新
{
	RgbWrite(ColorArr, RGBNUMBER, which_rgb);
}



void TestFun(uint8_t *pRegH, uint8_t len, uint8_t which_rgb, uint32_t color)   //测试函数，本工程中未使用到
{
	for (uint8_t i = 0; i < len; i++)
	{
		SetColorArrs(color, 0, *(pRegH + i));
		RgbWrite(ColorArr, 60, which_rgb);
		HAL_Delay(30);
	}
}

void RgbShow_FFT_Mode1(void) //正常跳动，颜色改变，根据ColorChangeArr[]数组中的颜色进行轮询改变
{
	uint16_t rgbShow_Hight = fftMaxChoice() / 2;       //(为达到更好的显示效果，显示高度可进行优化)将RGB灯带要显示的颗数赋值为获取到的最大振幅值的一半，具体参考函数fftMaxChoice()
	
	static float flag = 0;
	if (flag < ARR_SIZE(ColorChangeArr))
	{
		flag += 0.04;      //降低颜色改变速率，否则颜色变化太快，效果不好
	}
	else
	{
		flag = 0.0;
	}
	SetColorArrs(ColorChangeArr[(int)flag], 0, rgbShow_Hight);    //设置颜色
	
	RgbUpData(10);   //更新PA10引脚上连接的灯带的颜色（写入设置的颜色至Rgb灯带中）
	RgbUpData(7);    //更新PA7引脚上连接的灯带的颜色（写入设置的颜色至Rgb灯带中）
}

void RgbShow_FFT_Mode2(uint8_t pos)   //从下至上跳动，颜色全部加深，	pos = 1代表红色渐变，pos=2代表绿色渐变，否则代表红色渐变，主函数中，pos每每秒变换一次，具体变换参考tim.c中函数，用到了定时器相关知识
{
	uint8_t rgbShow_Hight = fftMaxChoice() / 2;		//将RGB灯带要显示的颗数赋值为获取到的最大振幅值的一半
	ColorDeepen(0xff, 0x3c, pos, 0, rgbShow_Hight); //Color deepening when 'rgbShow_Hight' increased
	
	RgbUpData(10);
	RgbUpData(7);
}

void RgbShow_FFT_Mode4(uint8_t pos) //从下至上跳动，颜色逐渐加深，pos = 1代表红色渐变，pos=2代表绿色渐变，否则代表红色渐变
{
	
	uint8_t rgbShow_Hight = fftMaxChoice() / 2; //将RGB灯显示的颗数赋值为最大振幅值的一半
	ColorIncre(0xff, 0x3c, 0x00, pos, 0, rgbShow_Hight);
	
	RgbUpData(10);
	RgbUpData(7);
}

void RgbShow_FFT_Mode3(uint8_t pos) //中间向两边跳动,颜色全部加深
{
	uint8_t rgbShow_Hight = fftMaxChoice() / 2; //将RGB灯显示的颗数赋值为最大振幅值的一半
	if (rgbShow_Hight > RGBNUMBER)				//本工程中RGB灯共30颗，显示颗数值超过30颗时，重新赋值为30颗
	{
		rgbShow_Hight = RGBNUMBER;
	}
	else if (rgbShow_Hight < 1)
	{
		rgbShow_Hight = 1;
	}
	if (rgbShow_Hight == 2) //中间跳动模式下，为保证对称性，如果出现显示颗数为2时，重新赋值为3
	{
		rgbShow_Hight = 3;
	}

	ColorDeepen(0xff, 0x3c, pos, RGBNUMBER / 2 - rgbShow_Hight / 2, rgbShow_Hight); //Color deepening when 'rgbShow_Hight' increased
	RgbUpData(10);
	RgbUpData(7);
}

void RgbShow_FFT_Mode5(uint8_t pos) //中间向两边跳动，颜色逐渐加深
{
	uint8_t rgbShow_Hight = fftMaxChoice() / 2;   //将RGB灯显示的颗数赋值为最大振幅值的一半
	if (rgbShow_Hight > RGBNUMBER)				        //本工程中RGB灯共30颗，显示颗数值超过30颗时，重新赋值为30颗
	{
		rgbShow_Hight = RGBNUMBER;
	}
	else if (rgbShow_Hight < 1)
	{
		rgbShow_Hight = 1;
	}
	if (rgbShow_Hight == 2)     //中间跳动模式下，为保证对称性，如果出现显示颗数为2时，重新赋值为3
	{
		rgbShow_Hight = 3;
	}
	ColorIncre(0xff, 0x3c, 0x00, pos, RGBNUMBER / 2, rgbShow_Hight / 2);
	ColorIncre2(0xff, 0x3c, 0x00, pos, RGBNUMBER / 2, rgbShow_Hight / 2);
	RgbUpData(10);
	RgbUpData(7);
}

void RgbShow_FFT_Mode6(uint8_t pos)
{
	uint8_t rgbShow_Hight = fftMaxChoice() / 2;

	if (rgbShow_Hight > RGBNUMBER)     //本工程中RGB灯共30颗，显示颗数值超过30颗时，重新赋值为30颗
	{
		rgbShow_Hight = RGBNUMBER;
	}
	if (rgbShow_Hight < 1)
	{
		rgbShow_Hight = 1;
	}

	for (uint8_t i = 0; i < RGBNUMBER; i++)
	{
		ColorDeepen(0xff, 0x3c, pos, i, 5);    //流水灯，流动颗数为5颗
		RgbUpData(10);
		RgbUpData(7);
		HAL_Delay(30 - rgbShow_Hight);     //当获取的显示高度越大时，让流水灯流动得更快
	}
}

//0x3c3cff00 -> 0x0000ff00;

void ColorDeepen(uint8_t mainColor, uint8_t startColor, uint8_t pos, uint8_t rgbStartpos, uint8_t rgbShowLen) //颜色全部加深函数
{
	colorArrClear();
	RgbUnion color;
	if (pos == 1) //红色是主体   pos = 1
	{
		color.rgb.r = mainColor;
		color.rgb.b = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;

		color.rgb.b = color.rgb.b - 2 * rgbShowLen;
		color.rgb.g = color.rgb.g - 2 * rgbShowLen;

		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
		}
	}
	else if (pos == 2) //绿色是主体  pos = 2
	{
		color.rgb.g = mainColor;
		color.rgb.r = startColor;
		color.rgb.b = startColor;
		color.rgb.w = 0x00;

		color.rgb.b = color.rgb.b - 2 * rgbShowLen;
		color.rgb.r = color.rgb.r - 2 * rgbShowLen;

		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
		}
	}
	else //蓝色是主体  pos = 3
	{
		color.rgb.b = mainColor;
		color.rgb.r = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;

		color.rgb.g = color.rgb.g - 2 * rgbShowLen;
		color.rgb.r = color.rgb.r - 2 * rgbShowLen;

		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
		}
	}
}

void ColorIncre(uint8_t mainColor, uint8_t startColor, uint8_t endColor, uint8_t pos, uint8_t rgbStartpos, uint8_t rgbShowLen) //颜色逐渐加深函数
{
	colorArrClear();
	RgbUnion color;
	if (pos == 1) //红色是主体   pos = 1
	{
		color.rgb.r = mainColor;
		color.rgb.b = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
			color.rgb.b = color.rgb.b - colorIncNum;
			color.rgb.g = color.rgb.g - colorIncNum;
		}
	}
	else if (pos == 2) //绿色是主体  pos = 2
	{
		color.rgb.g = mainColor;
		color.rgb.r = startColor;
		color.rgb.b = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
			color.rgb.r = color.rgb.r - colorIncNum;
			color.rgb.b = color.rgb.b - colorIncNum;
		}
	}
	else //蓝色是主体  pos = 3
	{
		color.rgb.b = mainColor;
		color.rgb.r = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i < (rgbShowLen + rgbStartpos); i++)
		{
			ColorArr[i] = color.u32;
			color.rgb.r = color.rgb.r - colorIncNum;
			color.rgb.g = color.rgb.g - colorIncNum;
		}
	}
}

void ColorIncre2(uint8_t mainColor, uint8_t startColor, uint8_t endColor, uint8_t pos, uint8_t rgbStartpos, uint8_t rgbShowLen) //颜色逐渐加深函数
{
	RgbUnion color;
	if (pos == 1) //红色是主体   pos = 1
	{
		color.rgb.r = mainColor;
		color.rgb.b = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i > (rgbStartpos - rgbShowLen); i--)
		{
			ColorArr[i] = color.u32;
			color.rgb.b = color.rgb.b - colorIncNum;
			color.rgb.g = color.rgb.g - colorIncNum;
		}
	}
	else if (pos == 2) //绿色是主体  pos = 2
	{
		color.rgb.g = mainColor;
		color.rgb.r = startColor;
		color.rgb.b = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i > (rgbStartpos - rgbShowLen); i--)
		{
			ColorArr[i] = color.u32;
			color.rgb.r = color.rgb.r - colorIncNum;
			color.rgb.b = color.rgb.b - colorIncNum;
		}
	}
	else //蓝色是主体  pos = 3
	{
		color.rgb.b = mainColor;
		color.rgb.r = startColor;
		color.rgb.g = startColor;
		color.rgb.w = 0x00;
		uint8_t colorIncNum = (startColor - endColor) / rgbShowLen;
		for (uint8_t i = rgbStartpos; i > (rgbStartpos - rgbShowLen); i--)
		{
			ColorArr[i] = color.u32;
			color.rgb.r = color.rgb.r - colorIncNum;
			color.rgb.g = color.rgb.g - colorIncNum;
		}
	}
}
